import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.util.Vector;

/**
 *
 *@author Paul Ozog
 *
 * Implements a simple chat server using UDP.  
 *
 * "Chatting" works by maintaining a list of connected
 *  clients that have previously sent a GREETING.  All clients in
 *  this list will receive INCOMMING packets when any client sends
 *  a MESSAGE
 *
 * There is only one UDP socket, and only one thread of execution
 *
 * See ChatProtocol for the structure of the packets, etc. 
 */
public class ChatServer {
    //clientList is vector of form { client1:port1, client2:port, etc. }
    private static Vector<String> clientList;
    public static byte[] buf = new byte[256];
    public static DatagramSocket UDPSocket;
    public static int serverPort;


    /**
     * @param args - port number
     * @return none
     *
     * main routine, checks args and calls Run();
     *
     */
    public static void main (String[] args) {
	if (args.length != 1) {
	    printUsage();
	    System.exit(-1);
	} else {

	    try {
		serverPort = Integer.parseInt(args[0]);
		UDPSocket = new DatagramSocket(serverPort);
		Run();
	    } catch (java.net.SocketException e) {
		System.out.println(e);
	    } // end try catch

	} //end if

    } //end main


    /**
     * @param  None
     * @return None
     *
     * Print the usage of ChatServer
     *
     */
    public static void printUsage () {
	System.out.println("Usage: java ChatServer serverPort");
    }

    /**
     * @param None
     * @return None
     * 
     * Main execution of server happens here.  The server waits for 
     * UDP packets and calls handlePacket
     */
    public static void Run() {
	DatagramPacket p = new DatagramPacket(buf, buf.length);
	clientList = new Vector<String>(0);
	System.out.println("Server Initialized...");

	while (true) {

	    try {
		UDPSocket.receive(p);
		handlePacket(p);
	    } catch (java.io.IOException e) {
		System.out.println(e);
	    } //end try catch

	} //end while

    } //end Run

    /**
     * @param packet - DatagramPacket that contains a keyword and message
     * @return None
     *
     * Checks the clientList and packet's keywordID to see if 
     * the server should add a new client, notify clients, or
     * do nothing
     */
    public static void handlePacket (DatagramPacket packet) {
	String client;
	int clientPort;
	String clientID; //Of the form "host:port"
	String message;
	byte keywordID;

	client = packet.getAddress().getHostAddress();
	clientPort = packet.getPort();

	//clientID of the form "host:port"
	clientID = client + ":" + Integer.toString(clientPort);
	
	keywordID = ChatProtocol.extractKeywordID(packet);
	message   = ChatProtocol.extractMessage(packet);

	//The the packet received is a GREETING and the
	// clientID is NOT in the clientList, add clientID
	// to the clientList
	if (!clientList.contains(clientID) && 
	    keywordID == ChatProtocol.GREETING) {
	    System.out.println("Got GREETING from " + clientID + "\n");
	    clientList.add(clientID);
	    return;
	}
	
	//if a known client lists sends a MESSAGE
	// notify all clients in clientList of its
	// contents
	else if (clientList.contains(clientID) &&
		 keywordID == ChatProtocol.MESSAGE) {
	    System.out.println("Got MESSAGE from " + clientID + "...");
	    System.out.println("\t" + message);
	    System.out.println("Notifying clients...\n");
	    
	    notifyAllClients(message, client, clientPort);
	}

	//else, do nothing
	else {
	    return;
	} // end if

    } // end handlePacket

    /**
     * @param message - String representing message of received packet
     * @param client  - client IP address of received packet
     * @param clientPort - port from received port
     *
     * Sends an INCOMMING packet to all clients in clientList.
     * Calls the ChatProtocol class to build the packet
     */     
    public static void notifyAllClients(String message,
					String client, 
					int clientPort) {
	
	//foreach clientID in clientList, send an INCOMING packet 
	// containing <message from client using clientPort>
	for (int i=0; i<clientList.size(); i++) {
	    String currentClient = clientList.elementAt(i);
	    String[] clientArray = currentClient.split(":");
	    try {
		DatagramPacket sendPacket = 
		    ChatProtocol.createIncommingPacket(message,
						       InetAddress.getByName(client),
						       clientPort,
						       InetAddress.getByName(clientArray[0]),
						       Integer.parseInt(clientArray[1]));
		UDPSocket.send(sendPacket);
	    } catch (UnknownHostException e) {
		System.out.println(e);
	    } catch (IOException e) {
		System.out.println(e);
	    } //end try catch block		

	} // end for

    } //end notifyAllClients

} //end class
